package com.lry.basic.algorithm.common;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/6/27
 */
public class LikeSearch<T> {
    private final CharColumn<T>[] columns = new CharColumn[Character.MAX_VALUE];
    public CharColumn<T>[] getColumns(){
        return columns;
    }
    private final ReentrantReadWriteLock wrl = new ReentrantReadWriteLock();
    private final Lock r = wrl.readLock();
    private final Lock w =wrl.writeLock();

    public void put(T t,String value){
        char[] chars = value.toCharArray();
        for(int i=0;i<chars.length;i++){
            char c = chars[i];
            CharColumn<T> column = columns[c];
            if(null==column){
                column = new CharColumn<T>();
                columns[c] = column;
            }
            column.add(t,(byte)i);
        }
    }

    public Collection<T> search(String word,int limit) {
        char[] chars = word.toCharArray();
        int len = word.length();
        Context context = new Context();
        for (int i = 0; i < len; i++) {
            CharColumn<T> column = columns[chars[i]];
            if (null == column) {
                break;
            }
            if(!context.filter(column)){
                break;
            }
            len--;
        }
        if(len==0){
            return context.limit(limit);
        }
        return Collections.emptySet();
    }

    private class Context<T>{
        Map<T,byte[]> result;
        boolean used = false;

        private boolean filter(CharColumn<T> column){
            if(this.used==false){
                this.result = new TreeMap<>(column.poxIndex);
                this.used = true;
                return true;
            }
            boolean flag = false;
            Map<T,byte[]> newResult = new TreeMap<>();
            Set<Map.Entry<T,byte[]>> entrySet = column.poxIndex.entrySet();
            for (Map.Entry<T,byte[]> entry:entrySet) {
                T id = entry.getKey();
                byte[] charPox = entry.getValue();
                if(!result.containsKey(id)){
                    continue;
                }
                byte[] before = result.get(id);
                boolean in = false;
                for(byte pox: before){
                    if(contain(charPox,(byte)(pox+1))){
                        in = true;
                        break;
                    }
                }
                if(in){
                    flag = true;
                    newResult.put(id,charPox);
                }
            }
            result = newResult;
            return flag;
        }

        public Collection<T> limit(int limit){
            if(result.size()<=limit){
                return result.keySet();
            }
            Collection<T> ids = new TreeSet<>();
            for(T id:result.keySet()){
                ids.add(id);
                if(ids.size()>=limit){
                    break;
                }
            }
            return ids;
        }


    }



    private class CharColumn<T> {
        ConcurrentHashMap<T,byte[]>poxIndex = new ConcurrentHashMap<>();

        public void add(T t, byte pox){
            byte[] arr = poxIndex.get(t);
            if(null==arr){
                arr = new byte[]{pox};
            }else{
                arr = copy(arr,pox);
            }
            poxIndex.put(t,arr);
        }


        public boolean remove(T t){
            if(poxIndex.remove(t)!=null){
                return true;
            }
            return false;
        }

    }

    private boolean contain(byte[] charPox, byte b) {
        return false;
    }
    private byte[] copy(byte[] arr, byte pox) {
        return arr;
    }
}
